#include "area.h"

#include <algorithm>

namespace application {
namespace area {

Area::Area(const QString& areaId, QObject* parent)
    : QObject(parent)
    , m_areaId(areaId)
{
}

void Area::setBounds(const kernel::Position& topLeft, const kernel::Position& bottomRight) {
    m_topLeft = topLeft;
    m_bottomRight = bottomRight;
}

bool Area::isOccupied() const {
    return m_isOccupied;
}

bool Area::isOccupiedBy(int agvId) const {
    return m_occupyingAgvIds.contains(agvId);
}

bool Area::occupy(int agvId) {
    if (m_occupyingAgvIds.contains(agvId)) {
        m_occupyingAgvIds[agvId]++;
    } else {
        m_occupyingAgvIds.insert(agvId, 1);
    }

    bool wasOccupied = m_isOccupied;
    m_isOccupied = true;

    if (!wasOccupied) {
        emit occupationChanged(true);
    }

    return true;
}

bool Area::releaseOccupation(int agvId) {
    if (!m_occupyingAgvIds.contains(agvId)) {
        return false;
    }

    m_occupyingAgvIds[agvId]--;
    if (m_occupyingAgvIds[agvId] <= 0) {
        m_occupyingAgvIds.remove(agvId);
    }

    bool wasOccupied = m_isOccupied;
    m_isOccupied = !m_occupyingAgvIds.isEmpty();

    if (wasOccupied && !m_isOccupied) {
        emit occupationChanged(false);
    }

    return true;
}

void Area::enterArea(int agvId) {
    occupy(agvId);
    emit areaEntered(agvId, m_areaId);
}

void Area::exitArea(int agvId) {
    releaseOccupation(agvId);
    emit areaExited(agvId, m_areaId);
}

QList<int> Area::getOccupyingAgvIds() const {
    return m_occupyingAgvIds.keys();
}

bool Area::containsPoint(const kernel::Position& position) const
{
    const double minX = std::min(m_topLeft.x, m_bottomRight.x);
    const double maxX = std::max(m_topLeft.x, m_bottomRight.x);
    const double minY = std::min(m_topLeft.y, m_bottomRight.y);
    const double maxY = std::max(m_topLeft.y, m_bottomRight.y);

    return position.x >= minX && position.x <= maxX &&
           position.y >= minY && position.y <= maxY;
}

} // namespace area
} // namespace application
